#include <stdio.h>
#include <stdlib.h>
#include <nds.h>

#include <nds/arm9/exceptions.h>

// common headers
#include "common.h"

// local headers
#include "slibs.h"

#include "guru.h"

#ifndef DEBUG_MYGURU
void guruInit() {
    defaultExceptionHandler();
}
#else
static const char *registerNames[]={
    "r0" , "r1" , "r2" , "r3" , "r4" , "r5" , "r6" , "r7",
    "r8 ", "r9 ", "r10", "r11", "r12", "sp ", "lr ", "pc "
};

void myguru();
void printAddresses();
u32 getExceptionAddress( u32 opcodeAddress, u32 thumbState);

void guruInit() {
    setExceptionHandler(myguru);
}

void myguru() {
    iprintf("\n  /!\\ An exception occured /!\\\n  /!\\ Execution stopped !! /!\\");

    printAddresses();

    void check_all();   // check buffer overflow in allocated buffers
    check_all();

    iprintf("\nPress SELECT to get more info\n\x1b[2A");
    while(1) {
        scanKeys();
        if(keysDown()&KEY_SELECT) {
            int i;
            for(i=0; i<8; i++)  // print registers
                iprintf("\n  %s: %08X   %s: %08X",
                    registerNames[i], exceptionRegisters[i],
                    registerNames[i+8],exceptionRegisters[i+8]
                );
            u32 *stack=(u32 *)exceptionRegisters[13/*sp*/];
            for(i=0; i<10; i++) // print stack dump
                iprintf("\n  %08X: %08X %08X", (u32)&stack[i*2], stack[i*2], stack[(i*2)+1]);
        }
    }
}

void printAddresses() {
    u32 thumbState=((*(u32*)0x02FFFD90)&0x20);

    extern const char __itcm_start[];

    if((getCPSR()&0x1f)==0x17) {
        iprintf("\ndata abort!");

        u32 codeAddress=exceptionRegisters[15]-8;
        if(
            (codeAddress>0x02000000 && codeAddress<0x02400000) ||
            (codeAddress>(u32)__itcm_start && codeAddress<(u32)(__itcm_start + 32768))
        )
            iprintf("\nPC:0x%08X\nADDR:0x%08X", codeAddress, getExceptionAddress(codeAddress, thumbState));
        else
            iprintf("\nPC:0x%08X", codeAddress);
    }
    else {
        iprintf("\nundefined instruction!");

        iprintf("\nPC:0x%08X", exceptionRegisters[15]-(thumbState?2:4));
    }
}
#endif

asm(
"    .text          \n"
"    .thumb         \n"
"    .thumb_func    \n"
"    .global getSP  \n"
"getSP:             \n"
"    mov r0, sp     \n"
"    bx lr          \n"
);

